namespace Warehouse

open System.Windows.Data
open System.ComponentModel
open System.Linq
open System.Windows

open System.Printing
open System.Drawing.Imaging
open System.Windows.Media.Imaging
open System.IO
open System
open System.Collections.Generic

open FSharp.Windows

type BrandController(repository : DataModel.Repository) = 
    inherit Controller<BrandsEvents, BrandModel>()

    let barCodeItemsPerPage = 10

    override this.InitModel model = 
        model.Items <- 
            repository.Brands 
            |> Seq.map EntityModel.Load 
            |> CollectionView.ofSeq 
        model.Items.SortBy <@ fun b -> b.Name @>

    override this.Dispatcher = Sync << function
        | Save ok -> this.Save ok
        | New -> this.New
        | Delete -> this.Delete
        | SelectedChanged brand -> this.SelectedChanged brand
        | PrintBarCodes -> this.PrintBarCodes

    member this.Save ok model = 
        this.SaveBrand model.SelectedBrand
        ok()

    member private this.SaveBrand brand = 
        if brand.IsNewEntity || brand.IsChanged 
        then 
            if brand.ClientDefaultLitrSizePct = 0M then brand.ClientDefaultLitrSizePct <- brand.ClientDefaultRegularPct
            if brand.VendorDefaultLitrSizePct = 0M then brand.VendorDefaultLitrSizePct <- brand.VendorDefaultRegularPct
            brand.UpdateEntity()
            brand.SaveEntity repository    

    member this.New model = 
        let newBrand : BrandDetailsModel = Model.Create()
        newBrand.Name <- "New Brand"
        model.Items.Add newBrand
        model.SelectedBrand <- newBrand

    member this.Delete model = 
        let brand = model.SelectedBrand
        if MessageBox.ActionConfirmed(sprintf "Are you sure you want to delete brand %s?" brand.Name, "Delete brand")
        then
            if not brand.IsNewEntity then repository.DeleteObject brand.Entity
            assert (repository.SaveChanges() = 1)
            model.Items.Remove brand

    member this.SelectedChanged brand model = 
        if brand.IsNewEntity || brand.IsChanged 
        then
            if MessageBox.ActionConfirmed(sprintf "Brand %s is new or has been modified. Would you like to save it?" brand.Name, "Save changes")
            then 
                this.SaveBrand brand
            else
                if brand.IsNewEntity 
                then
                    model.Items.CancelNew()
                else
                    brand.DiscardChanges()
                
    member private this.GetBarCodeImage upc = 
        use maker = new SoftekBarcodeMakerLib2.BarcodeMaker(barcode = upc, Type = 2, ModuleSize = 2)
        let bi = BitmapImage()
        bi.BeginInit()
        let ms = new MemoryStream()
        maker.MakeBarcode().Save(ms, ImageFormat.Bmp)
        ms.Seek(0L, SeekOrigin.Begin) |> ignore
        bi.StreamSource <- ms
        bi.EndInit()
        bi

    member this.PrintBarCodes model = 
        let mutable area = null
        let xpsDoc = PrintQueue.CreateXpsDocumentWriter(&area)
        if area <> null
        then
            let outputSize = Size(area.MediaSizeWidth, area.MediaSizeHeight)
            let margin = 24.0

            assert (margin >= area.OriginWidth)
            assert (margin >= area.OriginHeight)
            assert (margin <= area.OriginWidth + area.ExtentWidth)
            assert (margin <= area.OriginHeight + area.ExtentHeight)
            
            let container = Controls.BarCodeItemControl()
            let xpsWriter = xpsDoc.CreateVisualsCollator()
            //1440*900
            try
                xpsWriter.BeginBatchWrite()
                        
                for group in model.SelectedBrand.Entity.Products().Buffer(barCodeItemsPerPage) do
                    container.DataContext <- group |> Seq.map(fun p ->
                        Dictionary(
                            dict [
                                "BarCodeImage", box(this.GetBarCodeImage(p.SKU))
                                "SKU", box p.SKU
                                "Brand", box p.ProductName.Brand.Name
                                "Product", box p.ProductName.Name
                                "Size", box(String.Format("{0} {1}", p.SizeOrColor, p.Unit.Name).Trim())
                            ]
                        )
                    ) 
                    container.Margin <- Thickness(margin, margin, margin, margin)
                    container.Measure outputSize
                    container.Arrange(Rect(outputSize))
                    container.UpdateLayout()
                    xpsWriter.Write container

                xpsWriter.EndBatchWrite()
            with :? PrintingCanceledException -> ()
            


